/****************************************************************************************
**  File: Vector3.hpp
**  Author: Asteroth
**  Date: 22/02/2009
****************************************************************************************/

#ifndef __VECTOR3_HPP__
#define __VECTOR3_HPP__

template <class T>
class Vector3x
{
    public:
        T X, Y, Z;

        // --- Constructors ----------------------------------------------------
        Vector3x();
        Vector3x(const Vector2x<T> &vec);
        Vector3x(const Vector3x<T> &vec);
        Vector3x(T x, T y, T z);

        // --- Operators -------------------------------------------------------
        // a = a   a *= matrix   a * matrix
        inline Vector3x<T> &operator = ( const Vector3x<T> &set );
        inline Vector3x<T> &operator ^= ( const Matrix4x4x<T> &mat );
        inline Vector3x<T> operator ^ ( const Matrix4x4x<T> &mat );
        // a += b   a -= b   a + b   a - b
        inline Vector3x<T> &operator += ( const Vector3x<T> &add );
        inline Vector3x<T> &operator -= ( const Vector3x<T> &sub );
        inline Vector3x<T> operator + ( const Vector3x<T> &add ) const;
        inline Vector3x<T> operator - ( const Vector3x<T> &sub ) const;
        inline Vector3x<T> operator - () const;
        // a *= scalar   a /= scalar   a * scalar   a / scalar
        inline Vector3x<T> &operator *= ( const T scalar );
        inline Vector3x<T> &operator /= ( const T scalar );
        inline Vector3x<T> operator * ( const T scalar ) const;
        inline Vector3x<T> operator / ( const T scalar ) const;
        // dot product: a || b
        inline T operator || ( const Vector3x<T> &dot ) const;
        // cross product: a && b
        inline Vector3x<T> operator && ( const Vector3x<T> &crs ) const;
        // normal: !a
        inline Vector3x<T> operator ! () const;
        // length: ~a
        inline T operator ~ () const;
};

typedef Vector3x<float> Vector3;

const Vector3 INF_VECTOR3 = Vector3(INFINITY, INFINITY, INFINITY);
const Vector3 ZERO_VECTOR3 = Vector3(0.0f, 0.0f, 0.0f);

template <class T> Vector3x<T>::Vector3x()
    { X = (T)0.0; Y = (T)0.0; Z = (T)0.0; }
template <class T> Vector3x<T>::Vector3x(const Vector2x<T> &vec)
    { X = vec.X; Y = vec.Y; Z = 0; }
template <class T> Vector3x<T>::Vector3x(const Vector3x<T> &vec)
    { X = vec.X; Y = vec.Y; Z = vec.Z; }
template <class T> Vector3x<T>::Vector3x(T x, T y, T z)
    { X = x; Y = y; Z = z;}

template <class T> inline Vector3x<T> &Vector3x<T>::operator = ( const Vector3x<T> &set )
    { X = set.X; Y = set.Y; Z = set.Z; return *this; }
template <class T> inline Vector3x<T> &Vector3x<T>::operator ^= ( const Matrix4x4x<T> &mat )
    { Vector3x<T> vec( *this );
    X = vec.X * mat.M[0] + vec.Y * mat.M[4] + vec.Z * mat.M[8] + mat.M[12];
    Y = vec.X * mat.M[1] + vec.Y * mat.M[5] + vec.Z * mat.M[9] + mat.M[13];
    Z = vec.X * mat.M[2] + vec.Y * mat.M[6] + vec.Z * mat.M[10] + mat.M[14];
    return *this; }
template <class T> inline Vector3x<T> Vector3x<T>::operator ^ ( const Matrix4x4x<T> &mat )
    { return Vector3x<T>(
        X * mat.M[0] + Y * mat.M[4] + Z * mat.M[8] + mat.M[12],
        X * mat.M[1] + Y * mat.M[5] + Z * mat.M[9] + mat.M[13],
        X * mat.M[2] + Y * mat.M[6] + Z * mat.M[10] + mat.M[14]); }
template <class T> inline Vector3x<T> &Vector3x<T>::operator += ( const Vector3x<T> &add )
    { X += add.X; Y += add.Y; Z += add.Z; return *this; }
template <class T> inline Vector3x<T> &Vector3x<T>::operator -= ( const Vector3x<T> &sub )
    { X -= sub.X; Y -= sub.Y; Z -= sub.Z; return *this; }
template <class T> inline Vector3x<T> Vector3x<T>::operator + ( const Vector3x<T> &add ) const
    { return Vector3x<T>( X + add.X, Y + add.Y, Z + add.Z ); }
template <class T> inline Vector3x<T> Vector3x<T>::operator - ( const Vector3x<T> &sub ) const
    { return Vector3x<T>( X - sub.X, Y - sub.Y, Z - sub.Z ); }
template <class T> inline Vector3x<T> Vector3x<T>::operator - () const
    { return Vector3x<T>( -X, -Y, -Z ); }
template <class T> inline Vector3x<T> &Vector3x<T>::operator *= ( const T scalar )
    { X *= scalar; Y *= scalar; Z *= scalar; return *this; }
template <class T> inline Vector3x<T> &Vector3x<T>::operator /= ( const T scalar )
    { X /= scalar; Y /= scalar; Z /= scalar; return *this; }
template <class T> inline Vector3x<T> Vector3x<T>::operator * ( const T scalar ) const
    { return Vector3x<T>( X * scalar, Y * scalar, Z * scalar ); }
template <class T> inline Vector3x<T> Vector3x<T>::operator / ( const T scalar ) const
    { return Vector3x<T>( X / scalar, Y / scalar, Z / scalar ); }
template <class T> inline T Vector3x<T>::operator || ( const Vector3x<T> &dot ) const
    { return X * dot.X + Y * dot.Y + Z * dot.Z; }
template <class T> inline Vector3x<T> Vector3x<T>::operator && ( const Vector3x<T> &crs ) const
    { return Vector3x<T>( Y * crs.Z - Z * crs.Y, Z * crs.X - X * crs.Z, X * crs.Y - Y * crs.X ); }
template <class T> inline Vector3x<T> Vector3x<T>::operator ! () const
    { float len = sqrt( X * X + Y * Y + Z * Z );
    if ( len == 0 ) len = 1;
    return Vector3x<T>( X / len, Y / len, Z / len ); }
template <class T> inline T Vector3x<T>::operator ~ () const
    { return sqrt( X * X + Y * Y + Z * Z ); }

#endif
